package com.gzc.just.play.last.war.sceneserver.gs;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Component
public class GateServerManager {
    private static final Logger log = LoggerFactory.getLogger(GateServerManager.class);

    @Value("${scene.server.port:50001}")
    private int sceneServerPort;

    @Value("${scene.server.password:test_password}")
    private String sceneServerPassword;

    private final Map<Integer, GateServerInfo> gateServers = new ConcurrentHashMap<>();
    private final Map<String, GateServerInfo> channelIdToServerMap = new ConcurrentHashMap<>();
    private final Map<Channel, GateServerInfo> channelToServerMap = new ConcurrentHashMap<>();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
    
    protected ScheduledExecutorService createScheduler() {
        return scheduler;
    }

    @PostConstruct
    public void init() {
        log.info("Initializing GateServer manager, listenPort={}, password=***", sceneServerPort);
        scheduler.scheduleAtFixedRate(this::checkConnections, 30, 30, TimeUnit.SECONDS);
    }

    @PreDestroy
    public void destroy() {
        log.info("Shutting down GateServer manager");
        scheduler.shutdownNow();
    }

    public void addGateServer(Channel channel, GateServerInfo serverInfo) {
        if (channel == null || serverInfo == null) {
            log.warn("Cannot add GateServer, channel or info is null");
            return;
        }

        serverInfo.setChannel(channel);
        serverInfo.updatePingTime();
        gateServers.put(serverInfo.getServerId(), serverInfo);
        channelIdToServerMap.put(channel.id().asLongText(), serverInfo);
        channelToServerMap.put(channel, serverInfo);

        log.info("Added GateServer: id={}, remote={} ", serverInfo.getServerId(), serverInfo.getRemoteAddress());
    }

    public void onGateServerAuthenticated(GateServerInfo serverInfo) {
        if (serverInfo == null) {
            return;
        }
        serverInfo.setAuthenticated(true);
        log.info("GateServer authenticated: id={}", serverInfo.getServerId());
    }

    public void onGateServerDisconnected(GateServerInfo serverInfo) {
        if (serverInfo == null) {
            return;
        }

        log.warn("GateServer disconnected: id={}", serverInfo.getServerId());
        gateServers.remove(serverInfo.getServerId());
        if (serverInfo.getChannelId() != null) {
            channelIdToServerMap.remove(serverInfo.getChannelId());
        }
        if (serverInfo.getChannel() != null) {
            channelToServerMap.remove(serverInfo.getChannel());
        }
    }

    public void onClientMessage(int sessionId, int messageId, String message) {
        log.info("Processing client message: sessionId={}, messageId={} message={} ", sessionId, messageId, message);
        GateServerInfo availableServer = gateServers.values().stream().findFirst().orElse(null);
        if (availableServer == null) {
            log.warn("No available GateServer to forward client message");
            return;
        }
        // TODO: build actual payload
    }

    public void sendToGateServer(Channel channel, int messageId, byte[] payload) {
        if (channel == null || !channel.isActive()) {
            log.warn("GateServer channel not active, cannot send message: {}", messageId);
            return;
        }
        if (payload == null || payload.length == 0) {
            log.warn("Payload is empty for message: {}", messageId);
            return;
        }

        channel.writeAndFlush(payload).addListener((ChannelFutureListener) future -> {
            if (future.isSuccess()) {
                log.debug("Message sent to GateServer: {}", messageId);
            } else {
                log.error("Failed to send message to GateServer: {}", messageId, future.cause());
            }
        });
    }

    public void broadcastToAllGS(byte[] payload, int messageId) {
        if (payload == null) {
            return;
        }
        for (GateServerInfo serverInfo : gateServers.values()) {
            sendToGateServer(serverInfo.getChannel(), messageId, payload);
        }
    }
    
    public GateServerInfo getGateServer(int serverId) {
        return gateServers.get(serverId);
    }
    
    public Map<Integer, GateServerInfo> getGateServersMap() {
        return new HashMap<>(gateServers);
    }
    
    public Map<Channel, GateServerInfo> getChannelToServerMap() {
        return new HashMap<>(channelToServerMap);
    }
    
    public Map<Integer, GateServerInfo> getActiveGateServers() {
        Map<Integer, GateServerInfo> activeServers = new HashMap<>();
        for (Map.Entry<Integer, GateServerInfo> entry : gateServers.entrySet()) {
            Channel channel = null;
            // 查找对应的通道
            for (Map.Entry<Channel, GateServerInfo> channelEntry : channelToServerMap.entrySet()) {
                if (channelEntry.getValue().equals(entry.getValue())) {
                    channel = channelEntry.getKey();
                    break;
                }
            }
            
            if (channel != null && channel.isActive()) {
                activeServers.put(entry.getKey(), entry.getValue());
            }
        }
        return activeServers;
    }
    
    public int getGateServerCount() {
        return gateServers.size();
    }
    
    public void removeGateServer(Channel channel) {
        GateServerInfo serverInfo = channelToServerMap.get(channel);
        if (serverInfo != null) {
            gateServers.remove(serverInfo.getServerId());
            channelToServerMap.remove(channel);
            if (serverInfo.getChannelId() != null) {
                channelIdToServerMap.remove(serverInfo.getChannelId());
            }
            log.info("Removed GateServer: id={}", serverInfo.getServerId());
        }
    }
    
    public void broadcastToGateServers(int messageId, Object message) {
        for (GateServerInfo serverInfo : gateServers.values()) {
            if (serverInfo.getChannel() != null && serverInfo.getChannel().isActive()) {
                // TODO: 需要实现消息序列化逻辑
                // sendToGateServer(serverInfo.getChannel(), messageId, message);
            }
        }
    }

    private void checkConnections() {
        log.debug("Checking connections for {} GateServers", gateServers.size());
        long timeoutMillis = 60_000L;
        for (GateServerInfo serverInfo : gateServers.values()) {
            Channel channel = serverInfo.getChannel();
            if (channel == null || !channel.isActive()) {
                log.warn("GateServer {} connection lost", serverInfo.getServerId());
                removeGateServer(channel);
            } else if (serverInfo.isTimeout(timeoutMillis)) {
                log.warn("GateServer {} connection timeout, closing channel", serverInfo.getServerId());
                channel.close();
                onGateServerDisconnected(serverInfo);
            } else {
                serverInfo.updatePingTime();
            }
        }
    }

    public GateServerInfo getGSInfoByChannelId(String channelId) {
        return channelId == null ? null : channelIdToServerMap.get(channelId);
    }
    
    public GateServerInfo getGateServerByChannel(Channel channel) {
        return channelToServerMap.get(channel);
    }

    public Collection<GateServerInfo> getGateServers() {
        return Collections.unmodifiableCollection(gateServers.values());
    }
}
